<?php
// +----------------------------------------------------------------------
// | QSCMS
// +----------------------------------------------------------------------
// | Copyright (c)  2025 https://www.qqss.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed QSCMS is not free software, commercial use must purchase official license from official website to avoid unnecessary legal disputes.
// +----------------------------------------------------------------------
// | Author: Contract 990504246@qq.com
// +----------------------------------------------------------------------

namespace app\service\uploads;

use app\common\model\SystemUploads;
use getID3;

class UploadService
{
    /**
     * 根据文件扩展名判断文件类型
     * 
     * @param string $extension 文件扩展名
     * @return string 文件类型
     */
    protected function getFileTypeByExtension($extension)
    {
        $extension   = strtolower($extension);
        $mime_config = config('site.upload.mime');

        foreach ($mime_config as $type => $config) {
            if ($type !== 'all' && isset($config['ext']) && in_array($extension, $config['ext'])) {
                return $type;
            }
        }

        return 'other'; // 默认为其他类型
    }

    /**
     * 获取文件图标
     * 
     * @param string $extension 文件扩展名
     * @return string 文件图标
     */
    protected function getFileIcon($extension)
    {
        $extension = strtolower($extension);
        $icon_map  = config('site.upload.file_icon_map');

        if (isset($icon_map[$extension])) {
            return $icon_map[$extension];
        }

        // 如果没有找到扩展名对应的图标，则使用文件类型的默认图标
        $type        = $this->getFileTypeByExtension($extension);
        $mime_config = config('site.upload.mime');

        if (isset($mime_config[$type]['icon'])) {
            return $mime_config[$type]['icon'];
        }

        return 'file'; // 默认图标
    }

    /**
     * 获取上传文件的媒体信息（在上传前）
     * 
     * @param \Webman\Http\UploadFile $file 文件对象
     * @return array 包含文件类型和可能的时长信息
     */
    public function getMediaInfo(\Webman\Http\UploadFile $file)
    {
        $file_extension = strtolower($file->getUploadExtension());
        $file_mime      = $file->getUploadMimeType();
        $file_size      = $file->getSize();
        $file_name      = $file->getUploadName();

        $result = [
            'name' => $file_name,
            'size' => $file_size,
            'ext'  => $file_extension,
            'mime' => $file_mime,
            'type' => $this->getFileTypeByExtension($file_extension),
            'icon' => $this->getFileIcon($file_extension),
        ];

        // 如果是视频或音频文件，尝试获取时长
        if (in_array($result['type'], ['video', 'audio'])) {
            // 保存到临时目录获取时长后再删除
            $temp_dir = runtime_path() . '/temp';
            $this->mkdir($temp_dir);
            $temp_path = $temp_dir . '/' . uniqid() . '.' . $file_extension;

            // 复制文件到临时目录
            $file->move($temp_path);

            // 获取时长
            $duration = $this->getMediaDuration($temp_path);
            if ($duration > 0) {
                $result['duration'] = $duration;
            }

            // 删除临时文件
            if (file_exists($temp_path)) {
                unlink($temp_path);
            }
        }

        return $result;
    }

    /**
     * 文件上传
     * @param $app 所属应用
     * @param \Webman\Http\UploadFile $file 文件
     * @param $type 文件类型
     * @param $user_id  用户id
     * @param array $extra_data 额外数据，可以包含预先获取的时长等信息
     */
    public function upload($app, $file, $type, $user_id, $extra_data = [])
    {

        // 获取文件扩展名和MIME类型
        $file_extension = strtolower($file->getUploadExtension());
        $file_mime      = $file->getUploadMimeType();

        // 如果type为空或为auto，则根据文件扩展名自动判断类型
        if (empty($type) || $type === 'auto') {
            $type = $this->getFileTypeByExtension($file_extension);
        }

        // 获取配置的mime类型列表
        $mime_config = config('site.upload.mime');

        // 初始化为空变量，避免linter报错
        $detected_type = '';

        switch ($type) {
            case 'image':
            case 'video':
            case 'audio':
            case 'document':
            case 'spreadsheet':
            case 'presentation':
            case 'archive':
            case 'code':
            case 'other':
                $ext_yes = $mime_config[$type]['mime'];
                // 修改目录结构：按年/月-日存储
                $view_path = "/upload/{$type}/" . date('Y') . '/' . date('m-d') . '/';
                $real_path = public_path() . $view_path;
                break;
            case 'certificate':
                $ext_yes = $mime_config[$type]['mime'];
                // 证书文件上传到runtime目录 并根据日期创建文件夹 方便管理查找
                $view_path = "/crt/" . date('Ymd');
                $real_path = runtime_path() . $view_path;
                break;
            case 'all':
                // 合并所有类型的MIME类型
                $ext_yes = [];
                foreach ($mime_config as $config_type => $config) {
                    if ($config_type !== 'all' && isset($config['mime'])) {
                        $ext_yes = array_merge($ext_yes, $config['mime']);
                    }
                }
                // 修改目录结构：按年/月-日存储
                $view_path = "/upload/all/" . date('Y') . '/' . date('m-d') . '/';
                $real_path = public_path() . $view_path;
                // 根据文件扩展名检测真实类型
                $detected_type = $this->getFileTypeByExtension($file_extension);
                break;
            default:
                throw new \Exception('不支持的文件类型：' . $type);
        }

        // 检查MIME类型是否允许
        if (!in_array($file_mime, $ext_yes)) {
            // 尝试检查文件扩展名是否在允许列表中
            if ($type === 'all') {
                // 对于all类型，合并所有类型的扩展名
                $allowed_extensions = [];
                foreach ($mime_config as $config_type => $config) {
                    if ($config_type !== 'all' && isset($config['ext'])) {
                        $allowed_extensions = array_merge($allowed_extensions, $config['ext']);
                    }
                }
            } else {
                $allowed_extensions = $mime_config[$type]['ext'] ?? [];
            }

            if (!in_array($file_extension, $allowed_extensions)) {
                throw new \Exception('文件类型不允许，当前文件类型: ' . $file_mime . '，扩展名: ' . $file_extension);
            }
        }

        $this->mkdir($real_path);
        $name = $file->getUploadName();
        $size = $file->getSize();

        // 生成唯一文件名，避免同名文件覆盖
        $unique_name = time() . '_' . uniqid() . '.' . $file_extension;
        $file->move($real_path . '/' . $unique_name);

        // 如果是证书文件 返回本地绝对路径
        if ($type === 'certificate') {
            $file_url = $real_path . $unique_name;
        } else {
            // 如果使用站内资源
            $file_url = conf('site_domain') . $view_path . $unique_name;
        }

        // 获取文件图标
        $file_icon = $this->getFileIcon($file_extension);

        // 获取分类ID
        $cate_id = inputs('cate_id', 0);

        // 初始化数据库记录数据
        $upload_data = [
            'cate_id'       => $cate_id,
            'name'          => $file->getUploadName(), // 保存原始文件名
            'url'           => $file_url,
            'file_size'     => $size,
            'ext'           => $file_extension,
            'storage'       => 'local',
            'file_type'     => $type === 'all' ? $detected_type : $type,
            'file_icon'     => $file_icon,
            'original_name' => $name, // 添加原始文件名字段
        ];

        // 初始化返回结果数据
        $result = [
            'url'       => $file_url,
            'size'      => $size,
            'name'      => $file->getUploadName(),
            'ext'       => $file_extension,
            'type'      => $type === 'all' ? $detected_type : $type,
            'file_icon' => $file_icon,
        ];

        // 如果传入了额外数据中包含时长，直接使用
        if (isset($extra_data['duration']) && $extra_data['duration'] > 0) {
            $result['duration']      = $extra_data['duration'];
            $upload_data['duration'] = $extra_data['duration'];
        }
        // 否则，如果是视频或音频文件，尝试获取时长
        else {
            $file_type = $type === 'all' ? $detected_type : $type;
            if (in_array($file_type, ['video', 'audio'])) {
                $duration = $this->getMediaDuration($real_path . $unique_name);
                if ($duration > 0) {
                    $result['duration']      = $duration;
                    $upload_data['duration'] = $duration;
                }
            }
        }

        // 存储文件记录
        SystemUploads::create($upload_data);

        return $result;
    }

    /**
     * 目录创建
     */
    public function mkdir($path)
    {
        if (!is_dir($path)) {
            try {
                mkdir($path, 0777, true);
            } catch (\Exception $e) {
                throw new \Exception('目录创建失败');
            }
        }

        // 检查目录是否可写
        if (!is_writable($path)) {
            try {
                chmod($path, 0777);
            } catch (\Exception $e) {
                throw new \Exception('目录不可写');
            }
        }
    }

    /**
     * 获取媒体文件时长
     * @param string $filePath 文件路径
     * @return int 时长（秒）
     */
    private function getMediaDuration($filePath)
    {
        try {
            // 使用getid3库分析媒体文件
            $getID3   = new getID3();
            $fileInfo = $getID3->analyze($filePath);

            if (isset($fileInfo['playtime_seconds'])) {
                return (int) round($fileInfo['playtime_seconds']);
            }

            return 0;
        } catch (\Exception $e) {
            // 记录错误，但不影响上传
            // error_log('获取媒体时长失败: ' . $e->getMessage());
            return 0;
        }
    }

}